package com.urea.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.urea.common.core.domain.entity.SysUser;
import com.urea.common.exception.ServiceException;
import com.urea.common.utils.SecurityUtils;
import com.urea.common.utils.StringUtils;
import com.urea.system.config.MqttConsumerConfig;
import com.urea.system.constants.BusinessConstants;
import com.urea.system.domain.*;
import com.urea.system.domain.vo.*;
import com.urea.system.mapper.TerminalMapper;
import com.urea.system.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.urea.system.constants.BusinessConstants.NO;
import static com.urea.system.constants.BusinessConstants.YES;
import static java.util.function.Function.*;

/**
 * 终端Service业务层处理
 *
 * @author liuzd
 * @date 2023-08-01
 */
@Service
@Slf4j
public class TerminalServiceImpl extends ServiceImpl<TerminalMapper, Terminal> implements ITerminalService {
    @Autowired
    private TerminalMapper terminalMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private IFleetTerminalService fleetTerminalService;
    @Autowired
    private ITerminalConfigService configService;
    @Autowired
    private ITerminalLogService logService;
    @Autowired
    private ISysUserService userService;
    @Autowired
    private IBannerService bannerService;
    @Autowired
    private IFleetService fleetService;
    @Autowired
    private IPayInfoService payInfoService;
    @Autowired
    private IOrderService orderService;
    @Autowired
    private ITerminalNoticeService noticeService;
    @Autowired
    private IHardwareService hardwareService;
    @Autowired
    private ITerminalServiceInfoService terminalServiceInfoService;
    @Autowired
    private MqttConsumerConfig consumerConfig;

    @Value("${vicinity.distance}")
    private String distance;
    @Value("${spring.mqtt.customerTopic}")
    private String topic;
    @Value("${spring.mqtt.customerTopicCode}")
    private String code;



    /**
     * 查询终端
     *
     * @param id 终端主键
     * @return 终端
     */
    @Override
    public TerminalVo selectTerminalById(Long id) {
        return terminalMapper.selectTerminalById(id);
    }

    /**
     * 查询终端列表
     *
     * @param terminal 终端
     * @return 终端
     */
    @Override
    public List<TerminalVo> selectTerminalList(TerminalVo terminal) {
        SecurityUtils.getUserIdByUserType(terminal);
        List<TerminalVo> terminalVos = terminalMapper.selectTerminalList(terminal);
        if (CollectionUtils.isNotEmpty(terminalVos)) {
//            // 获取绑定车队信息
//            List<Long> tIds = terminalVos.stream().map(TerminalVo::getId).collect(Collectors.toList());
//            List<FleetTerminalVo> fleetTerminalVos = fleetTerminalService.queryTerminalFleetInfoByTId(tIds);
//            Map<Long, String> fleetNames = fleetTerminalVos.stream().collect(Collectors.groupingBy(FleetTerminalVo::getTerminalId,
//                    Collectors.mapping(FleetTerminalVo::getFleetName, Collectors.joining(","))));
            // 获取当月当天的加注数量
            List<Map<String, Object>> maps = logService.queryFillByDate();
            Map<String, List<Map<String, Object>>> fillList = maps.stream().collect(Collectors.groupingBy(m -> String.valueOf(m.get("terminalId"))));
            terminalVos.forEach(t -> {
//                t.setTerminalFleetName(fleetNames.get(t.getId()));
                List<Map<String, Object>> maps1 = fillList.get(String.valueOf(t.getId()));
                if (CollectionUtils.isNotEmpty(maps1)) {
                    Map<String, Object> fillMap = maps1.get(0);
                    t.setCurrDayFillCount(Objects.isNull(fillMap.get("dayCount")) ? BigDecimal.ZERO : (BigDecimal) fillMap.get("dayCount"));
                    t.setCurrMonthFillCount(Objects.isNull(fillMap.get("monthCount")) ? BigDecimal.ZERO : (BigDecimal) fillMap.get("monthCount"));
                }
            });
        }
        return terminalVos;
    }


    /**
     * 新增终端
     *
     * @param terminal 终端
     * @return 结果
     */
    @Override
    public void insertTerminal(TerminalVo terminal) {
        Terminal one = this.getOne(Wrappers.lambdaQuery(Terminal.class).eq(Terminal::getTerminalNo, terminal.getTerminalNo()));
        if (Objects.nonNull(one)) {
            throw new ServiceException("设备号已添加,请重新确认需要添加的设备");
        }

        if (StringUtils.equals(SecurityUtils.getLoginUser().getUser().getUserType(), "01")) {
            terminal.setAgentUid(SecurityUtils.getUserId());
        }
        terminal.setCurrentCapacity(new BigDecimal(BigInteger.ZERO));
        terminalMapper.insertTerminal(terminal);
        setDistinct(terminal.getTerminalNo(), terminal.getLatitude(), terminal.getLongitude());
        // 创建配置信息
        TerminalConfig config = new TerminalConfig();
        config.setTerminalId(terminal.getId());
        config.setPrice(terminal.getPrice());
        config.setPulse(terminal.getPulse());
        config.setTimeout(terminal.getTimeout());
        configService.save(config);
        // 当前容量 添加一个待处理
        doSaveNotice(terminal);
        // 订阅消息
        String topicName = topic.concat(terminal.getTerminalNo()).concat(code);
        consumerConfig.subscribe(topicName, 1);
        log.info("############订阅主题:{}成功############", topicName);
    }

    /**
     * 修改终端
     *
     * @param vo 终端
     * @return 结果
     */
    @Override
    public void updateTerminal(TerminalVo vo) {
        Terminal terminal = new Terminal();
        if (StringUtils.isNotBlank(vo.getTerminalNo())) {
            Terminal one = this.getOne(Wrappers.lambdaQuery(Terminal.class).eq(Terminal::getTerminalNo, terminal.getTerminalNo()));
            if (Objects.nonNull(one) && !one.getId().equals(vo.getId())) {
                throw new ServiceException("设备号已添加,请重新确认需要添加的设备");
            }
        }
        Terminal dbTerminal = getById(vo.getId());
        BeanUtils.copyProperties(vo, terminal);
        setDistinct(terminal.getTerminalNo(), terminal.getLatitude(), terminal.getLongitude());
        terminalMapper.updateTerminal(terminal);
        TerminalConfig config = configService.getOne(Wrappers.lambdaQuery(TerminalConfig.class).eq(TerminalConfig::getTerminalId, vo.getId()));
        // 修改配置信息
        boolean flag = false;
        TerminalConfig update = new TerminalConfig();
        update.setId(config.getId());
        if (!config.getPrice().equals(vo.getPrice())) {
            flag = true;
            update.setPrice(vo.getPrice());
        }
        if (!config.getPulse().equals(vo.getPulse())) {
            flag = true;
            update.setPulse(vo.getPulse());
        }
        if (!config.getTimeout().equals(vo.getTimeout())) {
            flag = true;
            update.setTimeout(vo.getTimeout());
        }
        if (flag) {
            configService.updateById(update);
        }
        if (Objects.nonNull(dbTerminal) && !Objects.equals(dbTerminal.getModel(), vo.getModel())) {
            hardwareService.config(vo.getPrice() + "", vo.getPulse() + "", vo.getModel(), vo.getModel() == 1 ? "120" : vo.getTimeout() + "", vo.getTerminalNo());
        }
        doSaveNotice(vo);
    }

    private void setDistinct(String terminalNo, BigDecimal latitude, BigDecimal longitude) {
        if (Objects.isNull(latitude) || Objects.isNull(longitude)) {
            return;
        }
        redisTemplate.opsForGeo().add(BusinessConstants.REDIS_TERMINAL_KEY, new RedisGeoCommands.GeoLocation(terminalNo, new Point(longitude.doubleValue(), latitude.doubleValue())));
    }

    private void doSaveNotice(TerminalVo vo) {
        // 当前容量 添加一个待处理
        List<TerminalNotice> list = noticeService.list(Wrappers.lambdaQuery(TerminalNotice.class).eq(TerminalNotice::getNotice, "尿素容量不足").eq(TerminalNotice::getStatus, 0).eq(TerminalNotice::getTerminalId, vo.getId()));
        if (Objects.isNull(list)) {
            TerminalNotice notice = new TerminalNotice();
            notice.setTerminalId(vo.getId());
            notice.setNoticeType(0);
            notice.setTerminalCapacity(BigDecimal.ZERO);
            notice.setNotice("尿素容量不足");
            noticeService.save(notice);
        }
    }

    /**
     * 批量删除终端
     *
     * @param ids 需要删除的终端主键
     * @return 结果
     */
    @Override
    public int deleteTerminalByIds(Long[] ids) {
        return terminalMapper.deleteTerminalByIds(ids);
    }

    /**
     * 删除终端信息
     *
     * @param id 终端主键
     * @return 结果
     */
    @Override
    public int deleteTerminalById(Long id) {
        return terminalMapper.deleteTerminalById(id);
    }

    /**
     * 获取附近列表
     *
     * @param longitude 经度
     * @param latitude  纬度
     * @return 结果
     */
    @Override
    public List<TerminalGEOVo> vicinityList(String longitude, String latitude) {
        // 根据经纬度 redis查出附近的列表
        Point point = new Point(Double.parseDouble(longitude), Double.parseDouble(latitude));
        // 半径
        Distance dis = new Distance(Double.parseDouble(distance), RedisGeoCommands.DistanceUnit.KILOMETERS);
        //
        Circle circle = new Circle(point, dis);
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs()
                //包含距离
                .includeDistance()
                //包含经纬度
                .includeCoordinates()
                //升序
                .sortAscending().limit(10);
        GeoResults radius = redisTemplate.opsForGeo().radius(BusinessConstants.REDIS_TERMINAL_KEY, circle, args);
        List<GeoResult<RedisGeoCommands.GeoLocation<String>>> content = radius.getContent();
        if (CollUtil.isNotEmpty(content)) {
            List<String> terminalNos = content.stream().map(e -> e.getContent().getName()).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(terminalNos)) {
                Map<String, Terminal> terminalMap = lambdaQuery().in(Terminal::getTerminalNo, terminalNos).list().stream().collect(Collectors.toMap(Terminal::getTerminalNo, identity()));
                return content.stream().map(e -> new TerminalGEOVo(terminalMap.get(e.getContent().getName()), e.getDistance().getValue())).collect(Collectors.toList());
            }

        }
        return Lists.newArrayList();
    }

    /**
     * 根据设备号查询设备信息
     *
     * @param terminalNo 设备号
     * @return 结果
     */
    @Override
    public TerminalVo getInfoByNo(String terminalNo) {
        Terminal terminal = baseMapper.selectOne(Wrappers.lambdaQuery(Terminal.class).eq(Terminal::getTerminalNo, terminalNo));
        if (Objects.isNull(terminal)) {
            throw new ServiceException("根据设备号为找到设备!");
        }
        // 判断用户是否属于当前车队
        TerminalVo vo = new TerminalVo();
        // 存在故障信息未处理
        List<TerminalNotice> list = noticeService.list(Wrappers.lambdaQuery(TerminalNotice.class).eq(TerminalNotice::getTerminalId, terminal.getId()).eq(TerminalNotice::getNoticeType, 1).eq(TerminalNotice::getStatus, "0"));
        if (CollectionUtils.isNotEmpty(list)) {
            vo.setNoticeType(1);
        } else {
            vo.setNoticeType(0);
        }
        BeanUtils.copyProperties(terminal, vo);
        Long userId = SecurityUtils.getUserId();
        FleetTerminalVo fleetTerminalVo = fleetTerminalService.checkUserInFleet(userId, terminal.getId());
        if (Objects.isNull(fleetTerminalVo)) {
            vo.setIsFleet("0");
        } else {
            vo.setIsFleet("1");
        }
        return vo;
    }

    /**
     * 根据创建人查询终端数量
     *
     * @param userId  渠道商id
     * @param agentId 供应商id
     * @return 结果
     */
    @Override
    public List<TerminalVo> getCountByCreateId(Long userId, Long agentId, Long storeId) {
        return baseMapper.getCountByCreateId(userId, agentId, storeId);
    }

    /**
     * 根据供应商id或者终端商id 获取车队数
     *
     * @param userId  终端商id
     * @param agentId 供应商id
     * @return 结果
     */
    @Override
    public Long queryFleetCountByUidOrTid(Long userId, Long agentId, Long storeId) {
        return baseMapper.queryFleetCountByUidOrTid(userId, agentId, storeId);
    }

    /**
     * 获取代理商或渠道商列表
     *
     * @param type 01代理商 02渠道商
     * @return 列表
     */
    @Override
    public List<SysUser> queryUserList(String type) {
        SysUser param = new SysUser();
        param.setUserType(type);
        return userService.queryUserList(param);
    }

    /**
     * 根据条件查询供应商数量
     *
     * @param vo 条件
     * @return 数量
     */
    @Override
    public Long selectAgentCountByCondition(CustomerVo vo) {
        return baseMapper.selectAgentCountByCondition(vo);
    }

    /**
     * 根据条件查询车队数量
     *
     * @param vo 条件
     * @return 数量
     */
    @Override
    public Long selectFleetCountByCondition(CustomerVo vo) {
        return baseMapper.selectFleetCountByCondition(vo);
    }

    /**
     * 根据条件查询车队用户数量
     *
     * @param vo 条件
     * @return 数量
     */
    @Override
    public Long selectFleetUserCountByCondition(CustomerVo vo) {
        return baseMapper.selectFleetUserCountByCondition(vo);
    }

    /**
     * 查询门店数量
     *
     * @param userId  终端商id
     * @param agentId 代理商id
     * @param storeId 门店id
     * @return 结果
     */
    @Override
    public Long queryStoreCount(Long userId, Long agentId, Long storeId) {
        return baseMapper.queryStoreCount(userId, agentId, storeId);
    }

    /**
     * pc代理商统计数据
     *
     * @return 结果
     */
    @Override
    public HomeVo statistics() {
        List<Map<String, Object>> list = baseMapper.statistics();
        HomeVo result = new HomeVo();
        result.setAgentList(list);
        // 代理商总数
        result.setAgentCount(userService.selectCountByUserType("01"));
        // 门店
        result.setStoreCount(userService.selectCountByUserType("04"));
        // 广告
        result.setBannerCount(bannerService.count());
        // 车队
        result.setFleetCount(fleetService.count());
        // 充值订单
        result.setFillCount(payInfoService.count(Wrappers.lambdaQuery(PayInfo.class).eq(PayInfo::getPayMethod, 0)));
        // 充值金额
        result.setFillAmount(orderService.selectSumAmount(0));
        return result;
    }

    @Override
    public void setUnpaid() {
        lambdaUpdate().set(Terminal::getEnable, NO).lt(Terminal::getUseExpiredTime, LocalDateTime.now()).update();
    }

    @Override
    public void assignTerminal(TerminalVo terminal) {
        Terminal entity = getById(terminal.getId());
        if (Objects.isNull(entity)) {
            throw new ServiceException("终端不存在");
        }
        if (Objects.isNull(terminal.getStoreUid())) {
            throw new ServiceException("门店信息不能为空");
        }

        entity.setAssign(YES);
        entity.setStoreUid(terminal.getStoreUid());
        terminalServiceInfoService.saveFirstTreminalServiceInfo(entity);
        saveOrUpdate(entity);
    }

    @Override
    public void renew(Order order) {
        Long terminalId = order.getTerminalId();
        Terminal terminal = getById(terminalId);
        LocalDateTime useExpiredTime = terminal.getUseExpiredTime();
        boolean before = useExpiredTime.isBefore(LocalDateTime.now());
        LocalDateTime newExpiredTime = before ? LocalDateTime.now().plusYears(1) : useExpiredTime.plusYears(1);
        terminal.setUseExpiredTime(newExpiredTime);
        terminal.setEnable(YES);
        log.info("终端续费成功，更新期限{}", terminal.toString());
        saveOrUpdate(terminal);
    }
}
